package core.utils;

import core.sb.SB;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JPanel;

/*Author: John Archer, Contact: john.archer.jpa@gmail.com*/
public class Utils {
    private static String CUR_PATH = ".";
    public static int [] getHPSLens(String tdna){
        ArrayList <String> hpsWords = new ArrayList();
        String hps;char sChar;int len;
        for(int t=0; t<tdna.length()-1; t++){
            sChar = tdna.charAt(t);
            len = 0;
            hps = tdna.charAt(t+len)+"";
            while(tdna.charAt(t+len+1)==sChar && (t+len+1)<tdna.length()-1){hps += tdna.charAt(t+(++len));}
            hpsWords.add(hps);
            t += len;
        }
        int [] hpsVals = new int[tdna.length()];
        int counter = 0;String word;
        for(int x=0; x<hpsWords.size(); x++){
            word = hpsWords.get(x);
            for(int i=0; i<word.length(); i++){hpsVals[counter++] = i;}
        }
        int [] hpsOrNot = new int[tdna.length()];
        hpsOrNot[0] = 0;
        for(int x=1; x<tdna.length(); x++){
            if(hpsVals[x-1] > 0 && hpsVals[x] == 0){hpsOrNot[x] = hpsVals[x-1];}
            else{ hpsOrNot[x] = hpsVals[x];}
        }
        return hpsOrNot;
    }

    public static char [] rpGaps(char [] con, String template){
        for(int c=0; c<con.length;c++){
            if(con[c]==SB.NUCS[SB.NUCS.length-1] || con[c]==SB.NUCS[SB.NUCS.length-2]){con[c] = template.charAt(c);}
        }
        return con;
    }

    public static String charToString(char [] chars){
        String str = "";
        for(int x=0; x<chars.length; x++){str += chars[x];}
        return str;
    }   

    public static char [] getCon(int[][]freqs, int minCoverForCon){
        char [] con = new char[freqs[0].length];
        int sum,highestCharacter,index;
        for(int x=0; x<freqs[0].length; x++){
            sum = 0;
            for(int y=0; y<freqs.length; y++){sum = sum + freqs[y][x];}
            if(sum>minCoverForCon){
                highestCharacter = -1;
                index = SB.NUCS.length;
                for(int y=0; y<freqs.length; y++){if(freqs[y][x] > highestCharacter){highestCharacter = freqs[y][x];index=y;}}
                con[x] = SB.NUCS[index];
            }
            else{con[x] = SB.NUCS[SB.NUCS.length-1];}
        }
        return con;
    }

    public static String getMatchingStrand(String strand) {
        String str = "";
        for (int x = 0; x < strand.length(); x++) {
            if (strand.charAt(x) == 'A') {str += "T";}
            else if (strand.charAt(x) == 'T'){str += "A";}
            else if (strand.charAt(x) == 'G') {str += "C";}
            else if (strand.charAt(x) == 'C') {str += "G";}
            else {str += strand.charAt(x);}
        }
        return str;
    }

    public static String getRevStr(String s) {
        String theString = s;
        char[] theChars = new char[theString.length()];
        char[] theNewChars = new char[theString.length()];
        for (int t = theChars.length - 1; t > 0; t--) {theChars[t] = theString.charAt(t);}
        for (int t = theChars.length - 1; t > 0; t--) {theNewChars[theChars.length - t] = theChars[t];}
        String theNewString = "";
        for (int t = 0; t < theNewChars.length; t++) {theNewString += "" + theNewChars[t];}
        return theNewString.trim();
    }

    //make cashed version of this so it is not so slow after first loading
    private static final JFileChooser chooser = new JFileChooser();
    public static JFileChooser getFile(JPanel menuObj, boolean opening) {
        try {
            chooser.setCurrentDirectory(new File(CUR_PATH));
            int r = 0;
            if (opening) {chooser.showOpenDialog(menuObj);}
            else {r = chooser.showSaveDialog(menuObj);}
            if (r == JFileChooser.APPROVE_OPTION) {
                CUR_PATH = chooser.getSelectedFile().getPath();
                return chooser;
            }
            else {return null;}
        } catch (Exception e){return null;}
    }

    public static void add(int [][] vals, int [][] matrixToAddTo){
        for(int t=0; t<vals.length; t++){
            for(int y=0; y<vals[t].length; y++){matrixToAddTo[t][y] += vals[t][y];}
        }
    }
    public static int sumOmitMax(int[] vals){
        int maxVal = vals[0];
        int iMax = 0;
        for (int i = 0; i < vals.length; i++) {
            if (vals[i] > maxVal) {
                maxVal = vals[i];
                iMax = i;
            }
        }
        int sum = 0;
        for (int z = 0; z < vals.length; z++){if (z != iMax) {sum += vals[z];}}
        return sum;
    }


    public static double getSecondHighestValue(double [] vals){
        double maxVal = vals[0];
        double secondMax = 0;
        for (int i = 0; i < vals.length; i++) {
            if (vals[i] > maxVal) {
                secondMax = maxVal;
                maxVal = vals[i];
            }
        }
        return secondMax;
    }


    public static double [][] dVToMat(double [] val, double [][] input){
        double [][] newMatrix = new double[input.length][input[0].length];
        for(int t=0; t<input.length; t++){
            for(int y=0; y<input[t].length; y++){
                if(val[y]>=1){
                    newMatrix[t][y] = input[t][y] / val[y];
                }
                else{
                    newMatrix[t][y] = 0.0;
                }
            }
        }
        return newMatrix;
    }

    public static double [][] addVal(double val, int [][] input){
        double [][] newMatrix = new double[input.length][input[0].length];
        for(int t=0; t<input.length; t++){
            for(int y=0; y<input[t].length; y++){
                newMatrix[t][y] = input[t][y] + val;
            }
        }
        return newMatrix;
    }

    public static double [] sumCols(double [][] in){
        double [] sum = new double[in[0].length];
        for(int col=0; col<in[0].length; col++){
            for(int row=0; row<in.length; row++){sum[col] = sum[col] + in[row][col];}
        }
        return sum;
    }

    public static int sum(int[] vals){
        int sum = 0;
        for (int z = 0; z < vals.length; z++){sum += vals[z];}
        return sum;
    }

    public static double myLog(int base, double val){return Math.log(val)/Math.log(base);}

    public static double getMean(int [] dataX){
        double sumation = 0.00;

        for(int x=0; x<dataX.length; x++){
            sumation  = sumation + (double)dataX[x];}
        return sumation/dataX.length;
    }


    public static double meanFromFreqArray(int [] dataX){
        ArrayList <Integer> vals = new ArrayList();
        for(int x=0; x<dataX.length; x++){
            for(int y=0; y<dataX[x]; y++){
                vals.add(x);
            }
        }

        int [] input = new int[vals.size()];
        for(int x=0; x<input.length; x++){input[x] = vals.get(x);}
        return getMean(input);
    }


    public static double getEnt(int a_a, int t_t, int g_g, int c_c, int gap, int cover){
        double ent = 0.00;double p;double cov = (double)cover;
        if(a_a>0){
            p = (double)a_a/cov;
            ent += (p * Utils.myLog(2, p));
        }
        if(t_t>0){
            p = (double)t_t/cov;
            ent +=(p * Utils.myLog(2, p));
        }
        if(g_g>0){
            p = (double)g_g/cov;
            ent +=(p * Utils.myLog(2, p));
        }
        if(c_c>0){
            p = (double)c_c/cov;
            ent +=(p * Utils.myLog(2, p));
        }
        if(gap>0){
            p = (double)gap/cov;
            ent +=(p * Utils.myLog(2, p));
        }
        ent = ent *(-1);
        return ent;
    }

    public static HashMap<String, Integer> sortHashMap(HashMap<String, Integer> input){
        Map<String, Integer> tempMap = new HashMap<String, Integer>();
        for (String wsState : input.keySet()){tempMap.put(wsState,input.get(wsState));}
        List<String> mapKeys = new ArrayList<String>(tempMap.keySet());
        List<Integer> mapValues = new ArrayList<Integer>(tempMap.values());
        HashMap <String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
        TreeSet <Integer> sortedSet = new TreeSet<Integer>(Collections.reverseOrder());
        sortedSet.addAll(mapValues);
        Object[] sortedArray = sortedSet.toArray();
        int size = sortedArray.length;
        for(int i=0; i<size; i++){sortedMap.put(mapKeys.get(mapValues.indexOf(sortedArray[i])), (Integer)sortedArray[i]);}
        return sortedMap;
    }

    public static int NO_OF_COLORS = 101;
    private static LinkedList <Color> AVAILABLE_COLORS_COLD_START = null;
    private static LinkedList <Color> getColors(){
        if(AVAILABLE_COLORS_COLD_START == null){
            AVAILABLE_COLORS_COLD_START = new LinkedList();
            LinkedList <Color> AVAILABLE_COLORS_HOT_START = new LinkedList();
            int red = 255;int green = 0;int blue = 0;
            LinkedList <Color> availableColors = new LinkedList();
            for(int x=1; x<=255; x++){availableColors.add(new Color(red, green++, blue));}
            for(int x=1; x<=255; x++){availableColors.add(new Color(red--, green, blue));}
            for(int x=1; x<=255; x++){availableColors.add(new Color(red, green, blue++));}
            for(int x=1; x<=255; x++){availableColors.add(new Color(red, green--, blue));}
            AVAILABLE_COLORS_HOT_START = availableColors;
            for(int x=AVAILABLE_COLORS_HOT_START.size()-1; x>=0; x--){AVAILABLE_COLORS_COLD_START.add(AVAILABLE_COLORS_HOT_START.get(x));}
        }
        return AVAILABLE_COLORS_COLD_START;
    }

    public static LinkedList <Color> getColors(int noOfColorsRequired){
        LinkedList <Color> allColorsAvailable = getColors();
        LinkedList <Color> requiredColors = new LinkedList();
        int stepSize = allColorsAvailable.size() / noOfColorsRequired;
        for(int step=0; step<allColorsAvailable.size(); step = step + stepSize){requiredColors.add(allColorsAvailable.get(step));}
        return requiredColors;
    }

    public static boolean getIUPACMatch(char char_1_barChar, char char_2){
        if(char_1_barChar==char_2){return true;}
        if(char_1_barChar=='M'){return (char_2=='A' || char_2=='C') ? true : false;}
        if(char_1_barChar=='R'){if(char_2=='A' || char_2=='G'){return true;}return false;}
        if(char_1_barChar=='W'){if(char_2=='A' || char_2=='T'){return true;}return false;}
        if(char_1_barChar=='S'){if(char_2=='C' || char_2=='G'){return true;}return false;}
        if(char_1_barChar=='Y'){if(char_2=='C' || char_2=='T'){return true;}return false;}
        if(char_1_barChar=='K'){if(char_2=='G' || char_2=='T'){return true;}return false;}
        if(char_1_barChar=='V'){if(char_2=='A' || char_2=='C' || char_2=='G'){return true;}return false;}
        if(char_1_barChar=='H'){if(char_2=='A' || char_2=='C' || char_2=='T'){return true;}return false;}
        if(char_1_barChar=='D'){if(char_2=='A' || char_2=='G' || char_2=='T'){return true;}return false;}
        if(char_1_barChar=='B'){if(char_2=='C' || char_2=='G' || char_2=='T'){return true;}return false;}
        if(char_1_barChar=='X'){if(char_2=='G' || char_2=='A' || char_2=='T' || char_2=='C'){return true;}return false;}
        if(char_1_barChar=='N'){if(char_2=='G' || char_2=='A' || char_2=='T' || char_2=='C'){return true;}return false;}
        return false;
    }

    public static JPanel getButton(JButton st, int width, int height, Color fCol, Color bCol, ActionListener al, String tooltip){
        st.setForeground(fCol);
        st.setBackground(bCol);
        st.setPreferredSize(new Dimension(width, height));
        st.addActionListener(al);
        st.setToolTipText(tooltip);
        JPanel p = new JPanel(new FlowLayout());
        p.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
        p.setOpaque(false);
        p.add(st);
        return p;
    }

    public static JPanel getButton(JButton st, int width, int height, Color fCol, Color bCol, ActionListener al, String tooltip, Font font){
        st.setForeground(fCol);
        st.setBackground(bCol);
        st.setPreferredSize(new Dimension(width, height));
        st.setFont(font);
        st.addActionListener(al);
        st.setToolTipText(tooltip);
        JPanel p = new JPanel(new FlowLayout());
        p.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
        p.setOpaque(false);
        p.add(st);
        return p;
    }

    public static JPanel getButton(JButton st, int width, int height, Color fCol, Color bCol, MouseListener ml, String tooltip){
        st.setForeground(fCol);
        st.setBackground(bCol);
        st.setPreferredSize(new Dimension(width, height));
        st.addMouseListener(ml);
        st.setToolTipText(tooltip);
        JPanel p = new JPanel(new FlowLayout());
        p.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
        p.setOpaque(false);
        p.add(st);
        return p;
    }

    public static String trans(String triplet){
        if(triplet.indexOf("-")!=-1){return "-";}
        final String translator[][]={{"GGG","GGA","GGT","GGC","GAG","GAA","GAT","GAC","GTG","GTA","GTT","GTC","GCG","GCA","GCT","GCC","AGG","AGA","AGT","AGC","AAG","AAA","AAT","AAC","ATG","ATA","ATT","ATC","ACG","ACA","ACT","ACC","TGG","TGA","TGT","TGC","TAG","TAA","TAT","TAC","TTG","TTA","TTT","TTC","TCG","TCA","TCT","TCC","CGG","CGA","CGT","CGC","CAG","CAA","CAT","CAC","CTG","CTA","CTT","CTC","CCG","CCA","CCT","CCC"},
                                 {"G",  "G",  "G",  "G",  "E",  "E",  "D",  "D",  "V",  "V",  "V",  "V",  "A",  "A",  "A",  "A",  "R",  "R",  "S",  "S",  "K",  "K",  "N",  "N",  "M",  "I",  "I",  "I",  "T",  "T",  "T",  "T",  "W",  "*",  "C",  "C",  "*",  "*",  "Y",  "Y",  "L",  "L",  "F",  "F",  "S",  "S",  "S",  "S",  "R",  "R",  "R",  "R",  "Q",  "Q",  "H",  "H",  "L",  "L",  "L",  "L",  "P",  "P",  "P",  "P"}};
        for(int z=0; z!=64; z++){if(translator[0][z].equals(triplet.toUpperCase())){return translator[1][z];}}
        return "?";
    }

    public static String getFrameTranslation(String toTranslate, int localFrame){
        String translation = "";
        while(localFrame<=toTranslate.length()-3){
          translation = translation + trans(toTranslate.substring(localFrame, localFrame+3));
          localFrame = localFrame+3;
       }
       return translation;
    }

    public static boolean isThereAStopCodonFreeTranslation(String seq){
        boolean stopFreeFrameExists = false;
        int frame=0;
        do{stopFreeFrameExists = (getFrameTranslation(seq, frame).indexOf("*") == -1) ? true : false;}
        while(stopFreeFrameExists==false && frame++<3);
        return stopFreeFrameExists;
    }
}